/*   Shotscreens
 *   Copyright (C) 2011, Andrew Lisin (http://crystalnix.com)
 *
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "tray.h"
#include "authdialog.h"
#include "fullscreenwidget.h"
#include "settings.h"
#include "Editor/screenshotseditor.h"
#include "Interfaces/settingsmenu.h"
#include "../pluginSDK/UploaderInterface.h"

#include <QAction>
#include <QApplication>
#include <QDesktopWidget>
#include <QList>
#include <QMessageBox>
#include <QPluginLoader>
#include <QString>

Tray::Tray(QObject *parent) :
    QSystemTrayIcon(parent),
    shortcut(this),
    fullscreenwidget(NULL),
    settingsMenu(NULL)

{
    createMenu();

    setContextMenu(&menu);

    createTray(); // set icon
    initializeTray(); // initialize nessesary connections
    initializeShortcut();
}

void Tray::createMenu()
{
    QList<QAction*> actions;

    // create actions
    actions.push_back(activityAction = new QAction(tr("Stop"), this));
    actions.push_back(captureAction = new QAction(tr("&Capture"), this));
    actions.push_back(settingsAction = new QAction(tr("Settings..."), this));
    actions.push_back(separator = menu.addSeparator()); // shit, but works
    actions.push_back(change_account = new QAction(tr("Change account..."), this));
    actions.push_back(quitAction = new QAction(tr("Quit"), this));
    //well done

    menu.addActions(actions); // add actions to menu
}

void Tray::createTray()
{
    QString icon_path;
    icon_path=icon_path.append(QApplication::applicationDirPath());
    icon_path=icon_path.append("/images/black.ico");
    setIcon(QIcon(":/images/black.ico"));    
}

void Tray::initializeTray()
{
    /* Here we initilize only those connections that are always used.
     * Connections that providing such things as tray <-> selecting widget,
     * tray <-> screenshot editor, tray <-> settings menu
     * will be created when these objects will be initialized.
     */

    // connections for menu actions:
    connect(activityAction, SIGNAL(triggered()), SLOT(changeActivity()));
    connect(captureAction, SIGNAL(triggered()), SLOT(takeScreenshot()));
    connect(settingsAction, SIGNAL(triggered()), SLOT(openSettingsMenu()));
    connect(change_account, SIGNAL(triggered()), SLOT(changeAccount()));

    // connecting shortcut:
    connect(&shortcut, SIGNAL(activated()), SLOT(takeScreenshot()));

    // quit:
    connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
}

// Methods' definition for active property:
bool Tray::isActive() const
{
    return active;
}

void Tray::setActive(bool state)
{
    active = state;
}
// active property's methods definition are done.


/* Slot that makes shortcut active/inactive.
 * When the application starts shortcut is always active.
 * This calls when user triggers the Start/Stop action in menu.
 * When been called slot changes activity to opposite.
 */
void Tray::changeActivity() {
    if(isActive())
    {
        setActive(false);
        disconnect(&shortcut, SIGNAL(activated()), this, SLOT(takeScreenshot()));
        activityAction->setText(tr("&Start")); // change text in menu action.
    }
    else
    {
        setActive(true);
        connect(&shortcut, SIGNAL(activated()), this, SLOT(takeScreenshot()));
        activityAction->setText(tr("&Stop")); // change text in menu action.
    }
}

void Tray::takeScreenshot()
{
    if(fullscreenwidget == NULL)
    {

        QPixmap screenOfDesktop; // here we put screenshot.
        screenOfDesktop = QPixmap(); // clear image for low memory situations
                                     // on embedded devices.
                                     // (See Qt Desktop->Screenshot example).
        screenOfDesktop = QPixmap::grabWindow(QApplication::desktop()->screen()->winId()); // getting screenshot of desktop.


        fullscreenwidget = new FullscreenWidget(screenOfDesktop, qobject_cast<QWidget*>(this));

        connect(fullscreenwidget, SIGNAL(pixmapSended(QPixmap)), SLOT(startEditor(QPixmap))); // now this connection is nessesary, so we make it.
        connect(fullscreenwidget, SIGNAL(destroyed()), SLOT(nullFullScrPtr())); // fullscreenwidget = NULL

        fullscreenwidget->showNormal();
    }
}

void Tray::nullFullScrPtr()
{
    fullscreenwidget = NULL;
}

void Tray::initializeShortcut()
{
    shortcut.setShortcut(Settings::instance().getKey());
}

void Tray::changeHotkey(QKeySequence key)
{
    Settings::instance().setKey(key);
    initializeShortcut();
}

/* Method creates and shows settings menu. Therу are some point about it.
 * We don't want user could create more then one copy of settings menu,
 * so we should looking for it. Wу initialize settings menu pointer by NULL
 * in constructor and creates a new copy only if pointer is NULL.
 * After deleting of settings menu object we call slot, that makes
 * pointer NULL again. It looks like very stupid method, and we should decide
 * what to do with it.
 */
void Tray::openSettingsMenu()
{    
    if(settingsMenu == NULL)
    {
        settingsMenu = new SettingsMenu(qobject_cast<QWidget*>(this));
        settingsMenu->setAttribute(Qt::WA_DeleteOnClose);

        connect(settingsMenu, SIGNAL(hotkeyLineEditHasBeenChanged(QKeySequence)), SLOT(changeHotkey(QKeySequence)));
        connect(settingsMenu, SIGNAL(destroyed()), SLOT(nullSettingsMenuPtr())); // magic call

        settingsMenu->raise();
        settingsMenu->show();
    }
}

void Tray::nullSettingsMenuPtr()
{
    settingsMenu = NULL; // set pointer to NULL
}

void Tray::startEditor(QPixmap background)
{

    QObject::sender()->deleteLater(); // not elegant, not Qt-way but effective.

    ScreenShotsEditor* screenshotsEditor = new ScreenShotsEditor(background, qobject_cast<QWidget*>(this));

    connect(screenshotsEditor, SIGNAL(uploadImage(QByteArray)), SLOT(uploadData(QByteArray))); // when finish with screenshot it is a time for saving it.

    screenshotsEditor->setAttribute(Qt::WA_DeleteOnClose);
    screenshotsEditor->show();
    screenshotsEditor->activateWindow();
}

void Tray::uploadData(QByteArray data) // uploading data according to selected plugin.
{
    if (data.isNull())
        return;
    QPluginLoader pl;
    QString str;
    QString plugin_name;

    //plugin_name = Settings::instance().getPluginFileName(); // getting plugin's name from settings
    plugin_name = Settings::instance().getUploader();

    if(plugin_name.length()<1) // if there is no plugin in settings
    {
    #ifdef Q_WS_MAC // Mac OS
        plugin_name = QString("libHttpSystem.1.0.0.dylib");
    #endif

    #ifdef Q_WS_WIN // Windows
        plugin_name = QString("libHttpSystem.1.0.0.dll"); // test this
    #endif
    }

    /* So we defined libHttpSystem as out default plugin */

    str=str.append(QApplication::applicationDirPath());
    str=str.append("/Plugins/");
    str=str.append(plugin_name);

    pl.setFileName(str);
    QObject *tmp = pl.instance();

    UploaderInterface * ui = qobject_cast<UploaderInterface *>(tmp);

    QString s;
    ui->GetPluginName(s);
    Settings::instance().setPluginName(s);

    ui->SetLoginAndPassword(QString(""),QString(""));
    ui->UploadStream(data);
}

void Tray::changeAccount() // change account "on fly"
{
    Settings::instance().setLogin(""); // reset login and password
    Settings::instance().setPassword("");

    AuthDialog *dialog = new AuthDialog(qobject_cast<QWidget*>(this)); // call authdialog to give a chanse to user to remember his login and password :)

    dialog->setAttribute(Qt::WA_DeleteOnClose);
    dialog->OnLoad();
    dialog->setModal(true);
    dialog->show();
}
